﻿using System;
using System.Collections.Generic;
using System.Text;

namespace ArcLine.ObjectClass
{
   public class Coor
    {
        public double X { get; set; }
        public double Y { get; set; }


        public Coor(double xp, double yp)
        {
            this.X = xp;
            this.Y = yp;
        }
    }

   public class SurveyPoint : Coor
   {
       public string Name { get; set; }
       public SurveyPoint(double xp, double yp)
           : base(xp, yp)
       {

       }
   }


   public class Line
   {
       public double A { get; set; }
       public double B { get; set; }
       public double C { get; set; }
       public Line(double a, double b, double c)
       {
           this.A = a;
           this.B = b;
           this.C = c;
       }

       public Line(SurveyPoint Node1, SurveyPoint Node2)
       {
           double F = Node2.X - Node1.X;
           double G = Node2.Y - Node1.Y;
           this.A = G;
           this.B = -F;
           this.C = -Node1.X * G + Node1.Y * F;
       }

   }

   public class SectionLine : Line
   {
       public SurveyPoint N1 { get; set; }
       public SurveyPoint N2 { get; set; }
       public SectionLine(SurveyPoint Node1, SurveyPoint Node2)
           : base(Node1, Node2)
       {
           N1 = Node1;
           N2 = Node2;
       }
   }

   public class ArcLine
   {
       public ArcLine() { }
       public Coor Center { get; set; }
       private double raduis = 0;
       public double Raduis { 
           get{return raduis;}
           set 
           {
               if (value < 0) { raduis = 0; }
               else { raduis = value; } 
           } 
       }
   }


   public class Intersect : IShapeObject
   {
       public static Coor IntersectwithSt(ArcLine arc, SectionLine line)
       {
           Intersect i = new Intersect();
           return i.IntersectWith(arc, line);
       }

       #region IShapeObject Members

       public Coor IntersectWith(ArcLine arc, SectionLine line)
       {
           Coor ped = Pedal(arc.Center, line);
           double chord = Chord(arc, line);
           double down = Math.Sqrt(line.A * line.A + line.B * line.B);
           Coor cor1, cor2;
           double x1 = ped.X + chord * line.B / down;
           double y1 = ped.Y - chord * line.A / down;
           double x2 = ped.X - chord * line.B / down;
           double y2 = ped.Y + chord * line.A / down;
           cor1 = new Coor(x1, y1);
           cor2 = new Coor(x2, y2);
           if (IsPointInSection(line, cor1))
           {
               return cor1;
           }
           if (IsPointInSection(line, cor2))
           {
               return cor2;
           }
           return null;

       }
       private Coor Pedal(Coor center, SectionLine line)
       {
           double A = line.A;
           double B = line.B;
           double C = line.C;
           double x1 = (B * B * center.X - A * B * center.Y - A * C) / (A * A + B * B);
           double y1 = (-A * B * center.X + A * A * center.Y - B * C) / (A * A + B * B);
           return new Coor(x1, y1);
       }

       private double Chord(ArcLine arc, SectionLine line)
       {
           double dist = Math.Abs(PtDistFrmLine(line, arc.Center));
           double c = Math.Sqrt(arc.Raduis * arc.Raduis - dist * dist);
           return Math.Round(c, 5);
           
       }

       private double PtDistFrmLine(Line l, Coor co)
        {
            try
            {
                double up = l.A * co.X + l.B * co.Y + l.C;
                double down = Math.Sqrt(l.A * l.A + l.B * l.B);
                return Math.Round(up / down, 5);
            }
            catch
            {
                return double.NaN;
            }
        }

       private bool IsPointInSection(SectionLine l, Coor cor)
       {
           double re = cor.X * l.A + cor.Y * l.B + l.C;
           if (re < 0.00001)
           {
               double maxX = l.N1.X > l.N2.X ? l.N1.X : l.N2.X;
               double minX = l.N1.X > l.N2.X ? l.N2.X : l.N1.X;
               double maxY = l.N1.Y > l.N2.Y ? l.N1.Y : l.N2.Y;
               double minY = l.N1.Y > l.N2.Y ? l.N2.Y : l.N1.Y;
               if (cor.X < maxX && cor.X > minX && cor.Y < maxY && cor.Y > minY)
               {
                   return true;
               }
          
           }
           return false;
       }
       #endregion
   }
}
